package hamsterpolice.todo;

import hamsterpolice.todo.data.DataNotFoundException;
import hamsterpolice.todo.data.DatabaseConstraintException;
import hamsterpolice.todo.model.Category;
import hamsterpolice.todo.model.ToDoItem;
import hamsterpolice.todo.model.ToDoItemCursorAdapter;
import hamsterpolice.todo.model.ToDoItemDataAdapter;
import hamsterpolice.todo.model.ToDoItemFilter;
import hamsterpolice.todo.model.User;

import java.util.ArrayList;

import android.app.Activity;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.text.format.Time;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

public class TodoListActivity extends ListActivity {

	private static final String TAG = "TodoListActivity";
	private static final int LOGIN_REQUEST = 1;
	private final static String LOGIN_PREFS = "LOGIN_PREFS";
	private final static String LOGIN_PREF_USER_ID = "USER_ID";
	private final static String BUNDLE_FILTER = "FILTER";
	private final static String ITEM_IDS = "ITEM_IDS";

	// PRIVATE VARIABLES

	private SharedPreferences mLoginPrefs = null;
	private User mLoggedIn = null;
	private ToDoItemFilter mFilter;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		if (savedInstanceState != null)
			mFilter = savedInstanceState.getParcelable(BUNDLE_FILTER);

		setContentView(R.layout.main);
		mLoginPrefs = getSharedPreferences(LOGIN_PREFS, MODE_PRIVATE);

		ListView lv = getListView();
		
		lv.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> av, View v, int pos,
					long id) {
				onListItemClick(v, pos, id);
			}			
		});
		
		lv.setLongClickable(true);
		lv.setOnItemLongClickListener(new OnItemLongClickListener() {
			@Override
			public boolean onItemLongClick(AdapterView<?> av, View v, int pos,
					long id) {
				return onListItemLongClick(v, pos, id);
			}
		});
		lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);

		outState.putParcelable(BUNDLE_FILTER, mFilter);
	}
	
	private void onListItemClick(View v, int pos, long id){
		Log.i(TAG, "onListItemClick id=" + id);
		
		ToDoItem item = null;
		try {
			item = ToDoItem.get(this, id);
		} catch (DataNotFoundException e) {
			Log.e(TAG, "Could not load item that was selected from list (id=" + id + ")");
			throw new RuntimeException(e);
		}
		item.setCompleted(!item.isCompleted());
		try {
			item.save();
		} catch (DatabaseConstraintException e) {
			Log.e(TAG, "Could not save item after toggling completed (id=" + id + ")");
			throw new RuntimeException(e);
		}
		
		View strikeThrough = v.findViewById(R.id.strikeThrough);
		strikeThrough.setVisibility(item.isCompleted() ? View.VISIBLE : View.GONE);
	}

	private boolean onListItemLongClick(View v, int pos, long id) {
		Log.i(TAG, "onLongListItemClick id=" + id);
		Intent editIntent = new Intent(this, EditToDoItemActivity.class);
		editIntent.putExtra(Editing.KEY_TODO_ITEM_ID, id);
		startActivity(editIntent);

		return true;
	}

	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.menu_list, menu);
		return true;
	}

	public boolean onOptionsItemSelected(MenuItem item) {
		// If this callback does not handle the item click,
		// onPerformDefaultAction
		// of the ActionProvider is invoked. Hence, the provider encapsulates
		// the
		// complete functionality of the menu item.
		switch (item.getItemId()) {
			case R.id.addButton:
	
				addNewItem();
				return false;
			case R.id.showMapButton:
				try {
	
					Intent registerIntent = new Intent(this,
							GoogleMapsActivity.class);
					registerIntent.putExtra(ITEM_IDS, getItemIds());

					startActivity(registerIntent);
	
				} catch (Exception e) {
					Log.e(TAG, "Error opening MapActivity", e);
				}
	
				return true;
			case R.id.showCompletedButton:
	
				if (item.isChecked()) {
					item.setChecked(false);
				} else {
					item.setChecked(true);
				}
				mFilter.setCompleted(item.isChecked());
				initializeListView();
				return true;
				
			case R.id.showDueBefore:
				if (item.isChecked()) {
					item.setChecked(false);
					mFilter.setDueBefore(null);
					initializeListView();
					
				} else {
					item.setChecked(true);
					setDueBefore(item);
				}

				return true;
				
			case R.id.showDueAfter:
				if (item.isChecked()) {
					item.setChecked(false);
					mFilter.setDueAfter(null);
					initializeListView();
				} else {
					item.setChecked(true);
					setDueAfter(item);
					
				}

				return true;
				
			case R.id.showProximity:
				if (item.isChecked()) {
					item.setChecked(false);
				//	mFilter.setShowProximity(null);  //needs to be implemented in the ToDoItemFilter
				//	initializeListView();
				} else {
					item.setChecked(true);
					setShowProximity(item);
					
				}	
				return true;
			
			case R.id.logoutButton:
				logout();
				return true;
		}
		return false;
	}

	private void setDueAfter(final MenuItem fItem) {
		final Dialog dueAfterDialog = new Dialog(TodoListActivity.this);
		dueAfterDialog.setContentView(R.layout.date_select);
		dueAfterDialog.setTitle(R.string.showDueAfter);
		dueAfterDialog.setCancelable(true);
		
		final DatePicker dueAfter = (DatePicker)dueAfterDialog.findViewById(R.id.datePicker);
		
		Time time = mFilter.getDueAfter();
		if(time!=null)
			dueAfter.init(time.year, time.month, time.monthDay, null);
		
		Button b = (Button)dueAfterDialog.findViewById(R.id.clearButton);
		b.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				mFilter.setDueAfter(null);
				fItem.setChecked(false);
				dueAfterDialog.dismiss();
				initializeListView();
			}
		});
		
		b = (Button)dueAfterDialog.findViewById(R.id.saveButton);
		b.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Time time = new Time();
				time.set(dueAfter.getDayOfMonth(), dueAfter.getMonth(), dueAfter.getYear());
				mFilter.setDueAfter(time);
				fItem.setChecked(true);
				dueAfterDialog.dismiss();
				initializeListView();
			}
		});
		
		dueAfterDialog.show();
	}

	private boolean setDueBefore(final MenuItem fItem) {
		final Dialog dueBeforeDialog = new Dialog(TodoListActivity.this);
		dueBeforeDialog.setContentView(R.layout.date_select);
		dueBeforeDialog.setTitle(R.string.showDueBefore);
		dueBeforeDialog.setCancelable(true);
		
		final DatePicker dueBefore = (DatePicker)dueBeforeDialog.findViewById(R.id.datePicker);
		
		Time time = mFilter.getDueBefore();
		if(time!=null)
			dueBefore.init(time.year, time.month, time.monthDay, null);
		
		Button b = (Button)dueBeforeDialog.findViewById(R.id.clearButton);
		b.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				mFilter.setDueBefore(null);
				fItem.setChecked(false);
				dueBeforeDialog.dismiss();
				initializeListView();
			}
		});
		
		b = (Button)dueBeforeDialog.findViewById(R.id.saveButton);
		b.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Time time = new Time();
				time.set(dueBefore.getDayOfMonth(), dueBefore.getMonth(), dueBefore.getYear());
				mFilter.setDueBefore(time);
				fItem.setChecked(true);
				dueBeforeDialog.dismiss();
				initializeListView();
			}
		});
		
		dueBeforeDialog.show();
		return true;
	}
	//TODO
	private boolean setShowProximity(final MenuItem fItem) {
		final Dialog proximityDialog = new Dialog(TodoListActivity.this);
		proximityDialog.setContentView(R.layout.number_select);
		proximityDialog.setTitle(R.string.showProximity);
		proximityDialog.setCancelable(true);
		
		final  TextView mView  = (TextView) proximityDialog.findViewById(R.id.number_selectTextField);
		
		Time time = mFilter.getDueBefore();
		if(time!=null)
			mView.setText("0");
		
		Button b = (Button)proximityDialog.findViewById(R.id.clearButton);
		b.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// mFilter.setFilter...(null);  TODO
				fItem.setChecked(false);
				proximityDialog.dismiss();
				//initializeListView();
			}
		});
		
		b = (Button)proximityDialog.findViewById(R.id.saveButton);
		b.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				/*int send mView.getText();//TODO needs Filter code
				mFilter.setDueBefore(time);
				fItem.setChecked(true);*/
				proximityDialog.dismiss();
				//initializeListView();
			}
		});
		
		proximityDialog.show();
		return true;
	}

	private void logout() {
		SharedPreferences.Editor ed = mLoginPrefs.edit();
		ed.remove(LOGIN_PREF_USER_ID);
		ed.commit();
		login();
	}

	private void addNewItem() {
		final Context context = this;
		final Dialog dialog = new Dialog(TodoListActivity.this);
		dialog.setContentView(R.layout.create_item);
		dialog.setTitle("Enter a new Todo Item");
		dialog.setCancelable(true);
		final EditText mEditItemName = (EditText) dialog
				.findViewById(R.id.editItemName);

		final Button saveButton = (Button) dialog
				.findViewById(R.id.saveButton);
		saveButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {

				String itemName = mEditItemName.getText().toString();

				if (itemName == null || itemName.trim().length() == 0) {
					Toast.makeText(v.getContext(), R.string.noItemName,
							Toast.LENGTH_SHORT).show();
					return;
				}

				try {
					ToDoItem item = new ToDoItem(context);
					item.setName(itemName);
					item.setUser(mLoggedIn);
					item.setCategory(mFilter.getCategory());
					item.save();
					dialog.dismiss();
					initializeListView();
				} catch (IllegalArgumentException e) {
					Log.e(TAG, "Error creating TodoItem", e);
				} catch (DatabaseConstraintException e) {
					Log.e(TAG,
							String.format(
									"Constraint error saving new ToDoItem with name = %s",
									itemName), e);
				}
			}
		});
		dialog.show();
	}

	/**
	 * Called just before activity is displayed and when activity returns to
	 * view
	 */
	@Override
	protected void onResume() {
		super.onResume();

		login();
	}

	/**
	 * Called when we receive a result from a called activity, like the Login
	 * activity
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		switch (requestCode) {
		case LOGIN_REQUEST:
			switch (resultCode) {
			case Activity.RESULT_OK:
				long userId = data.getLongExtra("USER_ID", -1);

				if (userId == -1) {
					Log.w(TAG,
							"LoginActivity reported success, but did not return a userid.");
				} else {
					try {
						mLoggedIn = User.get(this, userId);
						loggedIn();
					} catch (DataNotFoundException dnf) {
						Log.e(TAG,
								String.format(
										"UserID (%s) returned by login activity was not found in database!",
										userId));
					}
				}
				break;
			case Activity.RESULT_CANCELED:
				finish();
				break;
			}
			break;
		}
	}

	// ---------------------------------------------------------------------
	// Helper methods
	// ---------------------------------------------------------------------

	private void loggedIn() {
		SharedPreferences.Editor ed = mLoginPrefs.edit();
		ed.putLong(LOGIN_PREF_USER_ID, mLoggedIn.getID());
		ed.commit();

		// Temporary code to show that login worked
		TextView greeting = (TextView) findViewById(R.id.greeting);
		greeting.setText("Welcome, " + mLoggedIn.getUsername() + " !");

		if (mFilter == null || mFilter.getUser().getID() != mLoggedIn.getID())
			mFilter = new ToDoItemFilter(mLoggedIn);

		initializeCategorySpinner();

		initializeListView();

	}

	private void login() {
		long userId = mLoginPrefs.getLong(LOGIN_PREF_USER_ID, -1);
		if (userId == -1) {

			Intent loginIntent = new Intent(this, LoginActivity.class);
			startActivityForResult(loginIntent, LOGIN_REQUEST);
		} else {

			try {
				mLoggedIn = User.get(this, userId);
				loggedIn();
			} catch (DataNotFoundException dnf) {
				Log.e(TAG, String.format("UserID (%s) not found in database!",
						userId));
				logout();
			}
		}
	}

	private void initializeCategorySpinner() {

		ArrayList<Category> categoryList = (ArrayList<Category>) Category
				.getAll(this, mLoggedIn);
		Category all = new Category(this);
		all.setName("All Categories");
		Category newCategory = new Category(this);
		newCategory.setName("New...");
		categoryList.add(0, all);
		categoryList.add(1, newCategory);

		ArrayAdapter<Category> mAdapter = new ArrayAdapter<Category>(this,
				android.R.layout.simple_spinner_item, categoryList);

		Spinner s = (Spinner) findViewById(R.id.categorySpinner);

		s.setAdapter(mAdapter);
		
		s.setPromptId(R.string.chooseCategory);

		s.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> adapter, View v, int i,
					long lng) {

				if (i == 0) {
					mFilter.setCategory(null);
					initializeListView();
				} else if (i == 1) {
					addNewCategory();
					initializeCategorySpinner();
				} else {
					mFilter.setCategory((Category) adapter.getItemAtPosition(i));
					initializeListView();
				}
			}

			@Override
			public void onNothingSelected(AdapterView<?> arg0) {
				return;
			}
		});
	}
	
	private void addNewCategory() {
		final Context context = this;
		final Dialog dialog = new Dialog(TodoListActivity.this);
		dialog.setContentView(R.layout.create_category);
		dialog.setTitle("New Category");
		dialog.setCancelable(true);
		final EditText mEditCategoryName = (EditText) dialog
				.findViewById(R.id.editCategoryName);

		final Button cancelButton = (Button) dialog
				.findViewById(R.id.cancelCreateCategory);
		cancelButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				dialog.dismiss();

			}
		});

		final Button DoneButton = (Button) dialog
				.findViewById(R.id.doneCreateCategory);
		DoneButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {

				String categoryName = mEditCategoryName.getText().toString();

				if (categoryName == null || categoryName.trim().length() == 0) {
					Toast.makeText(v.getContext(), R.string.noCategoryName,
							Toast.LENGTH_SHORT).show();
					return;
				}

				try {
					Category category = new Category(context);
					category.setName(categoryName);
					category.setUser(mLoggedIn);
					category.save();
					dialog.dismiss();
					initializeCategorySpinner();
				} catch (IllegalArgumentException e) {
					Log.e(TAG, "Error creating Category", e);
				} catch (DatabaseConstraintException e) {
					Log.e(TAG,
							String.format(
									"Constraint error saving new Category with name = %s",
									categoryName), e);
				}
			}
		});
		dialog.show();
	}
	
	private long[] getItemIds() {
		Cursor c = ToDoItem.getCursor(this, mFilter);
		
		ArrayList<Long> itemIds = new ArrayList<Long>();
		ToDoItemDataAdapter adapter = new ToDoItemDataAdapter(this);
		while(c.moveToNext()){
			ToDoItem item = new ToDoItem(this);
			itemIds.add(adapter.load(c, item));
		}
		
		long[] ids = new long[itemIds.size()];
		for (int i=0; i<ids.length; i++) {
			ids[i] = itemIds.get(i);
		}
		return ids;
	}
	
	private void initializeListView() {
		if (mLoggedIn != null) {

			Cursor c = ToDoItem.getCursor(this, mFilter);
			
			setListAdapter(new ToDoItemCursorAdapter(this,
					R.layout.todo_list_item, c, null, null, 0));

		}
	}
}